#ifndef ENGINE_UTILS_H
#define ENGINE_UTILS_H

#include <string>

#include "engine.h"

// various helper utilities for the implementation of States, StateChanges, etc.



// serialization of strings: surround the string with quotes, and replace quotes
//  within the string with double-quotes
void serializeString(const std::string& s, std::ostream& ostr);
void unserializeString(std::string& s, std::istream& istr);


// check prefix when unserializing
template <class T> bool prefixMatch(const T& t, std::istream& istr)
{
	std::string prefix;
	istr >> prefix;
	return prefix == t.getPrefix();
}

// helper for serializing built-in types protected by a mask: serialize the mask first,
//  then, *if the mask is not HIDDEN*, the data as well
template <class T> void maskSerialize(const T& t, const PlayerMask& mask, std::ostream& ostr)
{
	ostr << mask;
	if (HIDDEN != mask)
		ostr << ' ' << t;
}
template <class T> void maskUnserialize(T& t, PlayerMask& mask, std::istream& istr)
{
	istr >> mask;
	if (HIDDEN != mask)
		istr >> t;
}


// default creation of censored serialization: make a copy, censor it, serialize it
template <class STATE> void censorAndSerialize(const STATE& state, const PlayerMask& mask, std::ostream& ostr)
{
	STATE statecopy = state;
	statecopy.censor(mask);
	statecopy.serialize(ostr);
}


// to redact is to destroy the information; to censor is to apply the mask, then redact if
//  necessary

// redact something: for built-in types just assign something, for others just
//  use default constructor
template <class T> void redact(T& t) {t = T();}
template <> void redact<int>(int& i) {i = 0;}
template <> void redact<bool>(bool& b) {b = false;}

// given an item of data, the mask protecting it, and the mask to be used for censorship,
//  perform the actual censorship
template <class T> void censorItem(T& t, PlayerMask& tmask, const PlayerMask& cmask)
{
	tmask &= cmask;
	if (HIDDEN == tmask)
		redact(t);
}

// censor two or three items protected by the same mask
template <class T1, class T2> void censorItems(T1& t1, T2& t2, PlayerMask& tmask, const PlayerMask& cmask)
{
	tmask &= cmask;
	if (HIDDEN == tmask)
	{
		redact(t1);
		redact(t2);
	}
}
template <class T1, class T2, class T3> void censorItems(T1& t1, T2& t2, T3& t3, PlayerMask& tmask, const PlayerMask& cmask)
{
	tmask &= cmask;
	if (HIDDEN == tmask)
	{
		redact(t1);
		redact(t2);
		redact(t3);
	}
}

// censor a container of items protected by a container of masks
// (assumes that the containers are the same size)
template <class TCON, class TMASKCON> void censorAll(TCON& tcon, TMASKCON& tmaskcon, const PlayerMask& cmask)
{
	typename TCON::iterator it = tcon.begin();
	for (typename TMASKCON::iterator maskit = tmaskcon.begin(); maskit != tmaskcon.end(); maskit++, it++)
	{
		PlayerMask& tmask = *maskit;  // make sure this is actually a container of PlayerMasks
		censorItem(*it, tmask, cmask);
	}
}

// same thing for multiple containers protected by same container of masks
template <class TCON1, class TCON2, class TMASKCON> void censorAll(TCON1& tcon1, TCON2& tcon2, TMASKCON& tmaskcon, const PlayerMask& cmask)
{
	typename TCON1::iterator it1 = tcon1.begin();
	typename TCON2::iterator it2 = tcon2.begin();
	for (typename TMASKCON::iterator maskit = tmaskcon.begin(); maskit != tmaskcon.end(); maskit++, it1++, it2++)
	{
		PlayerMask& tmask = *maskit;  // make sure this is actually a container of PlayerMasks
		censorItem(*it1, tmask, cmask);
		censorItem(*it2, tmask, cmask);
	}
}


#endif // ENGINE_UTILS_H